Telegram Group & Telegram Channel
🦾 Задача с подвохом: Виртуальные функции и конструкторы

Условие:

Что выведет следующий код и почему?


#include <iostream>

class Base {
public:
Base() {
std::cout << "Base constructor\n";
foo();
}
virtual void foo() {
std::cout << "Base foo\n";
}
};

class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor\n";
}
void foo() override {
std::cout << "Derived foo\n";
}
};

int main() {
Derived d;
return 0;
}


Вопрос:
Что будет выведено? Почему результат может удивить даже опытных C++ разработчиков?

🔍 Разбор:

1️⃣ Мы создаём объект
Derived d;.
Это вызывает конструктор
Derived, но сначала выполняется конструктор `Base` (по правилам иерархии).

2️⃣ В конструкторе
Base есть вызов foo();.
Может показаться, что поскольку объект на самом деле
Derived, вызовется Derived::foo().

Но! Вот главный подвох:

➡️ В C++, когда вы вызываете виртуальную функцию из конструктора (или деструктора), она не виртуальна для объекта, который ещё не полностью сконструирован.

На момент вызова
foo() объект всё ещё только Base, потому что Derived ещё не инициализирован.

Пошаговое выполнение:

- Вызов конструктора
Base:
```
Base constructor
```
- Вызов
foo() внутри конструктора Base:
Это вызовет Base::foo(), а не
Derived::foo():
```
Base foo
```
- После завершения конструктора
Base, вызывается конструктор Derived:
```
Derived constructor
```

Итоговый вывод:

```
Base constructor
Base foo
Derived constructor
```

💥 Подвох:

• Многие ожидают, что виртуальные функции работают «магически» всегда.
• Но при вызове из конструктора (или деструктора) виртуальные функции не полиморфны, потому что объект ещё не «стал» Derived полностью.

🛡️ Что нужно помнить:

Никогда не полагайтесь на вызовы виртуальных функций в конструкторах/деструкторах для вызова методов производных классов. Это источник трудноуловимых багов.

Вывод:

C++ строго следует правилам объектной модели: пока объект конструируется (или разрушается), он считается экземпляром того класса, конструктор которого выполняется в данный момент. Это поведение важно помнить при проектировании иерархий классов!


@cpluspluc



tg-me.com/cpluspluc/1066
Create:
Last Update:

🦾 Задача с подвохом: Виртуальные функции и конструкторы

Условие:

Что выведет следующий код и почему?


#include <iostream>

class Base {
public:
Base() {
std::cout << "Base constructor\n";
foo();
}
virtual void foo() {
std::cout << "Base foo\n";
}
};

class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor\n";
}
void foo() override {
std::cout << "Derived foo\n";
}
};

int main() {
Derived d;
return 0;
}


Вопрос:
Что будет выведено? Почему результат может удивить даже опытных C++ разработчиков?

🔍 Разбор:

1️⃣ Мы создаём объект
Derived d;.
Это вызывает конструктор
Derived, но сначала выполняется конструктор `Base` (по правилам иерархии).

2️⃣ В конструкторе
Base есть вызов foo();.
Может показаться, что поскольку объект на самом деле
Derived, вызовется Derived::foo().

Но! Вот главный подвох:

➡️ В C++, когда вы вызываете виртуальную функцию из конструктора (или деструктора), она не виртуальна для объекта, который ещё не полностью сконструирован.

На момент вызова
foo() объект всё ещё только Base, потому что Derived ещё не инициализирован.

Пошаговое выполнение:

- Вызов конструктора
Base:
```
Base constructor
```
- Вызов
foo() внутри конструктора Base:
Это вызовет Base::foo(), а не
Derived::foo():
```
Base foo
```
- После завершения конструктора
Base, вызывается конструктор Derived:
```
Derived constructor
```

Итоговый вывод:

```
Base constructor
Base foo
Derived constructor
```

💥 Подвох:

• Многие ожидают, что виртуальные функции работают «магически» всегда.
• Но при вызове из конструктора (или деструктора) виртуальные функции не полиморфны, потому что объект ещё не «стал» Derived полностью.

🛡️ Что нужно помнить:

Никогда не полагайтесь на вызовы виртуальных функций в конструкторах/деструкторах для вызова методов производных классов. Это источник трудноуловимых багов.

Вывод:

C++ строго следует правилам объектной модели: пока объект конструируется (или разрушается), он считается экземпляром того класса, конструктор которого выполняется в данный момент. Это поведение важно помнить при проектировании иерархий классов!


@cpluspluc

BY C++ Academy


Warning: Undefined variable $i in /var/www/tg-me/post.php on line 283

Share with your friend now:
tg-me.com/cpluspluc/1066

View MORE
Open in Telegram


C Academy Telegram | DID YOU KNOW?

Date: |

To pay the bills, Mr. Durov is issuing investors $1 billion to $1.5 billion of company debt, with the promise of discounted equity if the company eventually goes public, the people briefed on the plans said. He has also announced plans to start selling ads in public Telegram channels as soon as later this year, as well as offering other premium services for businesses and users.

However, analysts are positive on the stock now. “We have seen a huge downside movement in the stock due to the central electricity regulatory commission’s (CERC) order that seems to be negative from 2014-15 onwards but we cannot take a linear negative view on the stock and further downside movement on the stock is unlikely. Currently stock is underpriced. Investors can bet on it for a longer horizon," said Vivek Gupta, director research at CapitalVia Global Research.

C Academy from us


Telegram C++ Academy
FROM USA